#include <iostream>
#include <cstring>
#include <sys/socket.h>
#include "server.h"

#define RECVBUFSIZE 1024
#define TIMEBUFSIZE 1024
#define NAMEBUFSIZE 1024
#define INFOBUFSIZE 1024
#define FORWARDBUFSIZE 1024
#define CLIENTNAMESIZE 128

void *request_handler(void *arg)
{
	std::cout << "in request handler" << std::endl;
	struct THREADPARAM *threadparam = (struct THREADPARAM*)arg;
	struct CLIENTINFO client_info = threadparam->client_info;
	Server *server = threadparam->server;
	int client_fd = client_info.fd;
	char recvbuffer[RECVBUFSIZE];
	while(recv(client_fd, recvbuffer, sizeof(recvbuffer), 0) != -1)
	{
		std::cout << "recvbuffer: " << recvbuffer << std::endl;
		if(recvbuffer[0] == 't')
		{
			bool flag = false;
			std::cout << "request for time" << std::endl;
			flag = server-> send_time(client_fd);
			if(flag == false)
			{
				std::cout << "request for time failed" << std::endl;
			}
			else
			{
				std::cout << "request for time succeeded" << std::endl;
			}
		}
		else if(recvbuffer[0] == 'n')
		{
			std::cout << "request for name" << std::endl;
			bool flag = false;
			flag = server-> send_name(client_fd);
			if(flag == false)
			{
				std::cout << "request for name failed" << std::endl;
			}
			else
			{
				std::cout << "request for name succeeded" << std::endl;
			}
		}
		else if(recvbuffer[0] == 'i')
		{
			bool flag = false;
			std::cout << "request for all client's info" << std::endl;
			flag = server-> send_info(client_fd);
			if(flag == false)
			{
				std::cout << "request for client's info failed" << std::endl;
			}
			else
			{
				std::cout << "request for client's info succeeded" << std::endl;
			}
		}
		else if(recvbuffer[0] == 'f')
		{
			bool flag = false;
			bool change_flag = false;
			char target_name[CLIENTNAMESIZE];
			char forward_msg[FORWARDBUFSIZE] = "f ";
			std::cout << "request for forward send" << std::endl;
			for(int i = 2, j = 2; i <= strlen(recvbuffer); i++)
			{
				if(change_flag == true)
				{
					forward_msg[j] = recvbuffer[i];
					j++;
				}
				else
				{
					if(recvbuffer[i] == ' ')
					{
						change_flag = true;
						target_name[i-2] = '\0';
					}
					else
					{
						target_name[i-2] = recvbuffer[i];
					}
				}
			}
			flag = server-> send_msg(target_name, forward_msg);
			if(flag == false)
			{
				std::cout << "request for forward send failed" << std::endl;
				int answer_flag = -1;
				char answer_msg[] = "s fail";
				answer_flag = send(client_fd, answer_msg, sizeof(answer_msg), 0);
				if(answer_flag == -1)
				{
					std::cout << "answer for forward send failed" << std::endl;
				}
				else
				{
					std::cout << "answer for forward send succeeded" << std::endl;
				}
			}
			else
			{
				std::cout << "request for forward send succeeded" << std::endl;
				int answer_flag = -1;
				char answer_msg[] = "s success";
				answer_flag = send(client_fd, answer_msg, sizeof(answer_msg), 0);
				if(answer_flag == -1)
				{
					std::cout << "answer for forward send failed" << std::endl;
				}
				else
				{
					std::cout << "answer for forward send succeeded" << std::endl;
				}
			}
		}
		else if(strlen(recvbuffer) != 0)
		{
			std::cout << "\"" << recvbuffer << "\"" << std::endl;
			std::cout << "wrong request" << std::endl;
		}
		else
		{
			std::cout << client_info.name << " " << client_info.fd << " unlink" << std::endl;
			break;
		}
		memset(recvbuffer, '\0', sizeof(recvbuffer));
	}
	server->delete_fd(client_fd);
	pthread_exit(0);
}


Server::Server(std::string name, unsigned short sin_family, in_addr_t s_addr, unsigned short sin_port)
{
	std::cout << "create new server named " << name << std::endl;
	memset((void *)&server_addr, '\0', sizeof(server_addr));
	server_name = name;
	server_addr.sin_family = sin_family;			/* AF_INET: IPV4 communication domain */
	server_addr.sin_addr.s_addr = s_addr;			/* INADDR_ANY: accept any address */
	server_addr.sin_port = sin_port;

	server_sockfd = socket(AF_INET, SOCK_STREAM, 0); 		/* fd is file descriptor */
	if(server_sockfd == -1)
	{
  	std::cerr << "request for socket fails!" << std::endl;
  	
  	std::cerr << errno << std::endl;
	}
	int on;
  on = 1;
  setsockopt(server_sockfd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on));
  /* 端口复用，当关闭程序后又重新开启，绑定同一个端口号会出错，因为socket关闭后释放端口需要时间。*/
}

bool Server::initialize()
{
	int bind_flag = -1;
  int listen_flag = -1;
  int client_fd = -1;
  char client_name[CLIENTNAMESIZE] = "";									/* client name buffer */
  struct sockaddr_in client_addr;
  struct CLIENTINFO client_info;
  struct THREADPARAM threadparam;
  pthread_t tid_pointer;											/* thread id pointer */

  socklen_t client_socklen = sizeof(struct sockaddr_in);

	if(server_sockfd == -1)
	{
  	std::cerr << "request for socket fails!" << std::endl;
  	std::cerr << errno << std::endl;
  	return false;
	}
  else
  {
		bind_flag = bind(server_sockfd, (struct sockaddr *)&server_addr, sizeof(struct sockaddr));
		if(bind_flag == -1)
		{
			std::cerr << "request for bind fails!" << std::endl;
			std::cerr << errno << std::endl;
			return false;
		}
		listen_flag = listen(server_sockfd, 10);					/* arg2 is backlog, wait queue q0 size, max requests number same time */
		if(listen_flag == -1)
		{
			std::cerr << "request for listen fails!" << std::endl;
			return false;
		}
		else
		{
			std::cout << "start listening ... ..." << std::endl;
			while(1)																/* wait for connect and accept */
			{
				std::cout << "wait for accept ... ..." << std::endl;
				client_fd = accept(server_sockfd, (struct sockaddr *)&client_addr, &client_socklen);
				if(client_fd == -1)
				{
					std::cerr << "request for accept client socket fails!" << std::endl;
					return false;
				}
				else
				{
					int thread_error = 0;
					client_info.fd = client_fd;
					client_info.client_addr = client_addr;
					std::cout << "waiting for client's name ... ..." << std::endl;
					recv(client_fd, client_name, sizeof(client_name), 0);
					client_info.name = client_name;
					std::cout << "client: " << client_info.name << " connects"<< std::endl;
					client_infos.push_back(client_info);						/* save client's info */
					threadparam.client_info = client_info;
					threadparam.server = this;
					thread_error = pthread_create(&tid_pointer, NULL, request_handler, (void *)&threadparam);
					if(thread_error != 0)
					{
						std::cout << "create thread error: " << strerror(thread_error) << std::endl;
						return false;
					}
				}
			}
		}
		close(client_fd);
		close(server_sockfd);
		return true;
  }
}

bool Server::send_time(int client_fd)
{
	int flag = -1;
	time_t time_p;
	time(&time_p);
  char time_msg[TIMEBUFSIZE];
  memset(time_msg, '\0', strlen("t ") + sizeof(asctime(gmtime(&time_p))));
  strcat(time_msg, "t ");
  strcat(time_msg, asctime(gmtime(&time_p)));
  std::cout << time_msg << std::endl;
  flag = send(client_fd, time_msg, strlen(time_msg), 0);
  if(flag == -1)
  {
  	return false;
  }
  else
  {
  	return true;
  }
}

bool Server::send_name(int client_fd)
{
	int flag = -1;
	char name_msg[NAMEBUFSIZE];
	memset(name_msg, '\0', strlen("n ") + sizeof(server_name.c_str()));
	strcat(name_msg, "n ");
	strcat(name_msg, server_name.c_str());
	std::cout << "request for name: " << name_msg << std::endl;
	flag = send(client_fd, name_msg, strlen(name_msg), 0);
	if(flag == -1)
  {
  	return false;
  }
  else
  {
  	return true;
  }
}

bool Server::send_info(int client_fd)
{
  int flag = -1;
  char info_msg[INFOBUFSIZE];
  memset(info_msg, '\0', INFOBUFSIZE);
  strcat(info_msg, "i");
  std::vector<struct CLIENTINFO>::iterator it;					/* iterator */
  for(it=client_infos.begin(); it!=client_infos.end(); it++)
  {
  	strcat(info_msg, " ");
    strcat(info_msg, it->name.c_str());
    strcat(info_msg, " ");
    strcat(info_msg, std::to_string(it->fd).c_str());
		std::cout<< info_msg << std::endl;
	}
	flag = send(client_fd, info_msg, strlen(info_msg), 0);
	if(flag == -1)
	{
		std::cout << "fail to send info" << std::endl;
		return false;
	}
	else
	{
		std::cout << "info send succeeded" << std::endl;
		return true;
	}
}

bool Server::send_msg(char *name, char *forward_msg)
{
	//std::cout<< name << std::endl;
	//std::cout<< forward_msg << std::endl;
	bool find_flag = false;
	int flag = -1;
	std::vector<int> client_fds;
	std::vector<struct CLIENTINFO>::iterator it;					/* iterator */
  for(it=client_infos.begin(); it!=client_infos.end(); it++)
  {
  	if(strcmp(it->name.c_str(), name) == 0)
  	{
  		find_flag = true;
  		client_fds.push_back(it->fd);
  		// break;
  	}
  }
  if(find_flag == true)
  {
  	std::vector<int>::iterator fd_it;					/* client fds iterator */
		for(fd_it=client_fds.begin(); fd_it!=client_fds.end(); fd_it++)
		{
			flag = send(*fd_it, forward_msg, sizeof(forward_msg), 0);
			if(flag == -1)
			{
				return false;
			}
		}
		std::cout<< "forward message: " << forward_msg << std::endl;
		client_fds.clear();
		return true;
  }
  else
  {
  	std::cout << "not found" << std::endl;
  	return false;
  }
}

bool Server::delete_fd(int client_fd)
{
	bool delete_flag = false;
	std::vector<struct CLIENTINFO>::iterator it;					/* iterator */
  for(it=client_infos.begin(); it!=client_infos.end(); it++)
  {
  	if(it->fd == client_fd)
  	{
  		// std::cout << "delete: " << it->fd << std::endl;
  		it = client_infos.erase(it);
  		delete_flag = true;
  		break;
  	}
  }
  if(delete_flag == true)
  {
  	// std::cout << "deleted" << std::endl;
  	return true;
  }
  else
  {
  	std::cout << "not deleted" << std::endl;
  	return false;
  }
}
